package com.feng.spring.hibernate.extend.core;

import com.feng.spring.hibernate.extend.exception.HibernateExtendRuntimeException;
import com.feng.spring.hibernate.extend.core.sql.ParameterSQL;
import com.feng.spring.hibernate.extend.core.sql.PlaceholderSQL;
import com.feng.spring.hibernate.extend.core.sql.SQL;
import com.feng.spring.hibernate.extend.core.sql.StaticSQL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HibernateExtendSQLRegistry {

    private static final Logger logger = LoggerFactory.getLogger(HibernateExtendSQLRegistry.class);
    private final Pattern PLACEHOLDER = Pattern.compile("\\$\\{([a-zA-Z_][0-9a-zA-Z_]*)\\}|#\\{([a-zA-Z_][0-9a-zA-Z_]*)\\}");

    private Function<? super Class<?>, ? extends Map<String, List<SQL>>> mappingFunction = r -> new HashMap<>();

    private final Map<Class<?>, Map<String, List<SQL>>> sqlCache = new HashMap<>();

    public Class cache(String fileName, String sql) {
        if (fileName.toUpperCase().endsWith(".SQL")) {
            fileName = fileName.substring(0, fileName.lastIndexOf('.'));
        }
        String[] name = fileName.split("_");
        if (name.length != 2) {
            throw new HibernateExtendRuntimeException("SQL文件有误！文件名应该为:全类名+下划线+方法名");
        }
        Class clazz;
        try {
            clazz = ClassUtils.forName(name[0], null);
        } catch (ClassNotFoundException e) {
            throw new HibernateExtendRuntimeException("sql名称有误或类不存在:" + name[0]);
        }
        if (!ClassUtils.hasAtLeastOneMethodWithName(clazz, name[1])) {
            throw new HibernateExtendRuntimeException("方法名不存在:" + name[0] + "#" + name[1]);
        }

        List<SQL> sqls = new ArrayList<>();
        int start = 0;
        Matcher matcher = PLACEHOLDER.matcher(sql);
        while (matcher.find()) {
            sqls.add(new StaticSQL(sql.substring(start, matcher.start())));
            start = matcher.end();
            String holder = sql.substring(matcher.start(), matcher.end());
            if (holder.startsWith("#")) {
                sqls.add(new ParameterSQL(matcher.group(2)));
            } else if (holder.startsWith("$")) {
                sqls.add(new PlaceholderSQL(matcher.group(1)));
            }
        }
        if (sqls.size() == 0) {
            throw new HibernateExtendRuntimeException("sql解析出错:" + sql);
        }

        if (start < sql.length()) {
            sqls.add(new StaticSQL(sql.substring(start)));
        }

        Map<String, List<SQL>> methodMap = sqlCache.computeIfAbsent(clazz, mappingFunction);
        methodMap.put(name[1], sqls);
        logger.info("成功缓存文件：[{}.sql] 缓存sql：[{}]", fileName, sql);
        return clazz;
    }

    public List<SQL> get(Class c, String methodName) {
        Map<String, List<SQL>> methodMap = sqlCache.get(c);
        if (methodMap != null) {
            return methodMap.get(methodName);
        }
        return null;
    }
}
